summaryrefslogtreecommitdiff
path: root/src/pages/blog/read/[...slug].astro
diff options
context:
space:
mode:
Diffstat (limited to 'src/pages/blog/read/[...slug].astro')
-rw-r--r--src/pages/blog/read/[...slug].astro449
1 files changed, 0 insertions, 449 deletions
diff --git a/src/pages/blog/read/[...slug].astro b/src/pages/blog/read/[...slug].astro
deleted file mode 100644
index 71d0929..0000000
--- a/src/pages/blog/read/[...slug].astro
+++ /dev/null
@@ -1,449 +0,0 @@
----
-import { type CollectionEntry, getCollection } from "astro:content";
-import { render } from "astro:content";
-import Translations from "@components/Translations.astro";
-import { toIso8601Full } from "@utils/datetime";
-import ReadingTime from "@components/ReadingTime.astro";
-import Keywords from "@components/Keywords.astro";
-import Citations from "@components/Citations.astro";
-import Signature from "@components/signature/Signature.astro";
-import CopyrightNotice from "@components/CopyrightNotice.astro";
-import { verifier as verifierPrototype } from "@lib/pgp/verify";
-import { getSigners, isTranslation } from "@lib/collection/helpers";
-import { get } from "@utils/anonymous";
-import Authors from "@components/signature/Authors.astro";
-import { getEntry } from "astro:content";
-import Base from "@layouts/Base.astro";
-import readingTime from "reading-time";
-import type {
- Entry,
- MicroEntry,
- OriginalEntry,
-} from "@lib/collection/schemas";
-
-export async function getStaticPaths() {
- const posts = await getCollection("blog");
- return posts.map((post) => ({
- params: { slug: post.id },
- props: post,
- }));
-}
-
-type Props = CollectionEntry<"blog">;
-
-const post = Astro.props;
-
-let original: OriginalEntry | MicroEntry;
-if (isTranslation(post)) {
- original = await getEntry(post.data.translationOf) as
- | OriginalEntry
- | MicroEntry;
-
- if (!original) {
- throw new Error(`Original post not found for ${post.id}`);
- }
-
- const originalAuthor = (original.data.signers ?? []).filter(
- (s) => s.role === "author",
- ).map((s) => s.entity.id)?.[0];
- const originalCoAuthors = new Set(
- (original.data.signers ?? []).filter(
- (s) => s.role === "co-author",
- ).map((s) => s.entity.id),
- );
- const translationAuthor = (post.data.signers ?? []).filter(
- (s) => s.role === "author",
- ).map((s) => s.entity.id)?.[0];
- const translationCoAuthors = new Set(
- (post.data.signers ?? []).filter(
- (s) => s.role === "co-author",
- ).map((s) => s.entity.id),
- );
-
- if (
- (translationAuthor !== undefined &&
- translationAuthor !== originalAuthor) ||
- !translationCoAuthors.isSubsetOf(originalCoAuthors)
- ) {
- throw new Error(
- `Post ${post.id} has mismatched (co-)authors from original post ${original.id}`,
- );
- }
-
- const translators = (post.data.signers ?? []).filter(
- (s) => s.role === "translator",
- ).map((s) => s.entity.id);
-
- for (const translator of translators) {
- if (
- originalAuthor === translator || originalCoAuthors.has(translator)
- ) {
- throw new Error(
- `Translator ${translator} in ${post.id} is already a (co-)author in original post`,
- );
- }
- }
-} else {
- original = post;
- if (post.data.signers?.some((x) => x.role === "translator")) {
- throw new Error(
- `Post ${post.id} is not a translation but has translators defined`,
- );
- }
-}
-
-// Add own post as a translation
-const translationsSet = new Set(
- (await getCollection(
- "blog",
- (x) =>
- (x.data.kind === "translation") && x.data.translationOf.id ===
- (post.data.kind === "translation"
- ? post.data.translationOf.id
- : post.id),
- ) ?? []).map(({ id }) => id),
-);
-
-translationsSet.add(post.id);
-const translations = [...translationsSet.values()].map((id) => ({
- collection: post.collection,
- id,
-}));
-
-const signers = await getSigners(post);
-
-const verifier = await verifierPrototype.then((x) => x.clone());
-
-// Add signers public keys to keyring
-for (const { data } of signers.map(get("entity"))) {
- if (data.publickey.armor !== undefined) {
- verifier.addKeyFromArmor(data.publickey.armor);
- }
-}
-
-const verification = post.filePath !== undefined
- ? await verifier.verify([
- new URL(`file://${Deno.cwd()}/${post.filePath}`),
- ])
- : undefined;
-
-const { Content } = await render(post);
-
-const { lang } = post.data;
-
-const commit = await verification?.commit;
-
-const reading = post.body ? readingTime(post.body, {}) : undefined;
-const minutes = reading === undefined
- ? undefined
- : Math.ceil(reading.minutes);
-const estimative = reading === undefined
- ? undefined
- : new Intl.DurationFormat(lang, {
- style: "long",
- }).format({ minutes });
-const duration = minutes === undefined
- ? undefined
- : `PT${Math.floor(minutes / 60) > 0 ? Math.floor(minutes / 60) + "H" : ""}${
- minutes % 60 > 0 ? minutes % 60 + "M" : ""
- }`;
-
-const getOrUndefined = (k: string) =>
- k in post.data ? post.data[k as keyof typeof post.data] : undefined;
-const author = {
- "@type": "Person",
-} as const;
-const contributor = post.data.signers.filter(({ role }) =>
- role === "co-author"
-).map(() => {
- return {
- "@type": "Person",
- } as const;
-});
-const translator = post.data.signers.filter(({ role }) =>
- role === "translator"
-).map(() => {
- return {
- "@type": "Person",
- } as const;
-});
-const JSONLD = {
- "@context": "https://schema.org",
- "@type": "BlogPosting",
- "@id": Astro.url.href,
- articleBody: post.rendered?.html ?? post.body,
- abstract: getOrUndefined("description"),
- alternativeHeadline: getOrUndefined("subtitle"),
- author,
- citation: [].map(() => {
- return {
- "@type": "CreativeWork",
- };
- }),
- contributor,
- copyrightHolder: [author, ...contributor, ...translator],
- // copyrightNotice: post.data.license, // WORKAROUND
- copyrightYear: post.data.dateCreated.getFullYear(),
- creativeWorkStatus: "Published",
- dateCreated: post.data.dateCreated.toISOString(),
- dateModified: "dateUpdated" in post.data
- ? post.data.dateUpdated?.toISOString()
- : undefined,
- // datePublished: undefined, // from git commit commit date
- encodingFormat: "text/html",
- headline: post.data.title,
- inLanguage: post.data.lang,
- isAccessibleForFree: true,
- isBasedOn: isTranslation(post)
- ? {
- "@type": "BlogPosting",
- "@id": new URL(`blog/read/${post.data.translationOf}`, Astro.site).href,
- }
- : undefined,
- keywords: original.data.keywords,
- license: post.data.license, // WORKAROUND
- locationCreated: {
- "@type": "Place",
- // XXX: getOrUndefined("locationCreated"),
- },
- mentions: [].map(() => {
- return {
- "@type": "Thing",
- };
- }),
- // publication: {
- // "@type": "PublicationEvent",
- // }, // from git commit
- // publisher: {
- // "@type": "Person",
- // }, // from git commit
- text: post.rendered?.html ?? post.body,
- timeRequired: post.body !== undefined ? duration : undefined,
- translationOf: isTranslation(post)
- ? {
- "@type": "BlogPosting",
- "@id": new URL(`blog/read/${post.data.translationOf}`, Astro.site).href,
- }
- : undefined,
- translator,
- // version: undefined // TODO
- wordCount: reading?.words,
- workTranslations: translations.filter(({ id }) => id !== post.id).map((
- { id },
- ) => ({
- "@type": "BlogPosting",
- "@id": new URL(`blog/read/${id}`, Astro.site).href,
- })),
- description: getOrUndefined("description"),
- name: post.data.title,
- url: Astro.url.href,
-} as const;
----
-
-<Base
- title={post.data.title}
- description={"description" in post.data ? post.data.description : post.data.title}
->
- <main>
- <article
- itemscope
- itemtype="http://schema.org/BlogPosting"
- itemid={Astro.url.href}
- >
- <Translations {translations} {lang} />
- <hgroup>
- <h1 itemprop="headline">{post.data.title}</h1>
- {
- "subtitle" in post.data && (
- <p itemprop="alternativeHeadline" class="subtitle">
- {post.data.subtitle}
- </p>
- )
- }
- </hgroup>
- {
- "description" in post.data && post.data.description &&
- (
- <section itemprop="abstract">
- <h2>Resumo</h2>
- {
- post.data.description.split(new RegExp("\\s{2,}"))
- .map((
- x,
- ) => <p>{x}</p>)
- }
- </section>
- )
- }
- {verification && <Signature {lang} {verification} />}
- <footer>
- {
- verification?.verifications &&
- (
- <Authors
- verifications={verification.verifications}
- expectedSigners={signers}
- commitSignerKey={commit?.signature?.signer}
- />
- )
- }
- <dl>
- <dt>Data de criação</dt>
- <dd>
- <time
- itemprop="dateCreated"
- datetime={toIso8601Full(post.data.dateCreated)}
- >{
- new Intl.DateTimeFormat([lang], {}).format(
- post.data.dateCreated,
- )
- }</time>
- </dd>
- {
- post.data.dateUpdated && (
- <dt>Última atualização</dt><dd>
- <time
- itemprop="dateModified"
- datetime={toIso8601Full(post.data.dateUpdated)}
- >{
- new Intl.DateTimeFormat([lang], {}).format(
- post.data.dateUpdated,
- )
- }</time>
- </dd>
- )
- }
- {
- "locationCreated" in post.data &&
- post.data.locationCreated && (
- <dt
- itemprop="locationCreated"
- itemscope
- itemtype="https://schema.org/Place"
- >
- Local de criação
- </dt><dd>
- <span itemprop="name">{post.data.locationCreated}</span>
- </dd>
- )
- }
- </dl>
- <ReadingTime body={post.body} {lang} />
- </footer>
- <hr />
- <div itemprop="articleBody text"><Content /></div>
- <hr />
- {
- "keywords" in original.data && (
- <Keywords keywords={original.data.keywords} />
- )
- }
- {
- "relatedPosts" in original.data && (
- <Citations citations={original.data.relatedPosts} />
- )
- }
- <CopyrightNotice
- author={signers[0]?.entity.data.websites?.[0] ?? "Anonymous"}
- website={signers[0]?.entity.data.websites?.[0]}
- email={signers[0]?.entity.data.websites?.[0]}
- title={post.data.title}
- dateCreated={post.data.dateCreated}
- license={post.data.license}
- />
- </article>
- </main>
-</Base>
-
-<script
- type="application/ld+json"
- is:inline
- set:html={JSON.stringify(JSONLD)}
-/>
-
-<script type="module" is:inline>
- hashchange();
-
- window.addEventListener("hashchange", hashchange);
-
- document.addEventListener(
- "click",
- function (event) {
- if (
- event.target &&
- event.target instanceof HTMLAnchorElement &&
- event.target.href === location.href &&
- location.hash.length > 1
- ) {
- requestIdleCallback(function () {
- if (!event.defaultPrevented) {
- hashchange();
- }
- });
- }
- },
- false,
- );
-
- function hashchange() {
- let hash;
-
- try {
- hash = decodeURIComponent(location.hash.slice(1)).toLowerCase();
- } catch (e) {
- return;
- }
-
- const name = "user-content-" + hash;
- const target = document.getElementById(name) ||
- document.getElementsByName(name)[0];
-
- if (target) {
- requestIdleCallback(function () {
- target.scrollIntoView();
- });
- }
- }
-</script>
-
-<style is:inline>
- section[data-footnotes].footnotes {
- word-wrap: break-word;
- }
-</style>
-
-<style>
- hgroup {
- text-align: center;
- }
-
- .subtitle {
- font-weight: lighter;
- }
-
- [itemprop~="articleBody"] {
- line-height: 1.4;
- font-size: 1.2em;
- text-align: justify;
-
- & h1,
- & h2,
- & h3 {
- line-height: 1.2;
- }
- }
-
- [itemprop="abstract"] {
- margin-inline: 1em;
- padding-block: 1em;
- font-style: italic;
- }
-
- @media print {
- body {
- font-size: 1rem;
- font-family: var(--ff-serif);
- line-height: 1.62;
- }
- }
-</style>